package org.midy.infrastructure;

import org.midy.infrastructure.exception.SelectionKeyCancelException;
import org.midy.infrastructure.tools.Logger;
import sun.rmi.runtime.Log;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;

/**
 * 处理读事件处理
 */
public class WriteEventHandler implements EventHandler{

    boolean writeHead = true;
    int headLength = 8;
    @Override
    public Object handle(SelectionKey selectionKey) {
        ChannelEventHelper channelEventHelper = checkSelectKeyAndChannel(selectionKey);
        if(Objects.isNull(channelEventHelper) ) {
            return null;
        }

        selectionKey.interestOps(selectionKey.interestOps() & ~SelectionKey.OP_WRITE); // 取消监听写的事件, 完成协作
        SocketChannel socketChannel = channelEventHelper.getSocketChannel();

        BlockingQueue<ByteBuffer> sendMessageQueue = channelEventHelper.getSendMessageQueue();
        ByteBuffer sendByteBuffer = null;
        try {
            while ((sendByteBuffer = sendMessageQueue.poll()) != null) {
                if(writeHead) {
                    byte[] bytes = generateHeader(headLength, sendByteBuffer.remaining());
                    ByteBuffer wrapHead = ByteBuffer.wrap(bytes);
                    while (wrapHead.hasRemaining()) {
                        socketChannel.write(wrapHead);
                    }
                }
                while (sendByteBuffer.hasRemaining()) {
                    socketChannel.write(sendByteBuffer);
                }
                sendByteBuffer = null;
            }
        } catch (Throwable t) {
            Logger.error("写数据失败！", t);
            throw new RuntimeException(t); // 解决如果写这连接断开的情况下，需要注销该通道的所有事件监听和缓存（持久化）
        }

        return null;
    }

    public static byte[] generateHeader(int preLength, int body) {
        char[] chars = new char[preLength];
        String bodyStr = String.valueOf(body);
        int off = preLength - 1;
        for (int idx = bodyStr.length() - 1; idx >= 0; idx--) {
            chars[off--] = bodyStr.charAt(idx);
        }
        while (off >= 0) {
            chars[off--] = '0';
        }
        return new String(chars).getBytes();
    }
}
